import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
from sklearn.metrics import silhouette_score
import platform  # 用于判断操作系统

# 聚类方法类
class ClusterUtils(object):
    def __init__(self):
        self.df = pd.read_csv('scenic_data.csv')
        # 预处理：去除NaN值（避免聚类报错，之前的核心问题）
        self.df = self.df.dropna(subset=['non_weekend_ratio', 'elderly_ratio', 'out_province_ratio'])
        if len(self.df) == 0:
            raise ValueError("无有效数据（可能全是NaN），请检查scenic_data.csv")

    def get_k(self):
        """
        获取合适的k值
        """
        # 解决中文显示问题（关键配置）
        self._set_chinese_font()

        # 提取特征并标准化
        features = self.df[['non_weekend_ratio', 'elderly_ratio', 'out_province_ratio']]
        scaler = StandardScaler()
        scaled_features = scaler.fit_transform(features)
        
        # 计算不同k值下的轮廓系数
        silhouette_scores = []
        k_range = range(2, 11)
        for k in k_range:
            kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
            cluster_labels = kmeans.fit_predict(scaled_features)
            silhouette_avg = silhouette_score(scaled_features, cluster_labels)
            silhouette_scores.append(silhouette_avg)
        
        # 绘制轮廓系数曲线
        plt.plot(k_range, silhouette_scores, marker='o', linewidth=2, markersize=8)
        plt.title('轮廓系数法确定最优聚类数k', fontsize=14)  # 中文标题
        plt.xlabel('聚类数k', fontsize=12)  # 中文x轴标签
        plt.ylabel('轮廓系数', fontsize=12)  # 中文y轴标签
        plt.grid(True, alpha=0.3)  # 添加网格，提升可读性
        plt.xticks(k_range)
        # 标记最优k值
        optimal_k = k_range[silhouette_scores.index(max(silhouette_scores))]
        plt.scatter(optimal_k, max(silhouette_scores), color='red', s=100, zorder=5)
        plt.annotate(f'最优k={optimal_k}\n系数={max(silhouette_scores):.4f}', 
                     xy=(optimal_k, max(silhouette_scores)),
                     xytext=(optimal_k+0.5, max(silhouette_scores)-0.05),
                     arrowprops=dict(arrowstyle='->'))
        plt.show()

    def _set_chinese_font(self):
        """
        根据操作系统设置对应的中文字体
        """
        system = platform.system()
        try:
            if system == 'Windows':
                # Windows系统常见中文字体
                plt.rcParams['font.sans-serif'] = ['SimHei']  # 黑体（大部分Windows默认安装）
                # 备选字体：['Microsoft YaHei']（微软雅黑）、['SimSun']（宋体）
            elif system == 'macOS':
                # macOS系统常见中文字体
                plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
                # 备选字体：['Heiti TC']（黑体-繁）、['Songti SC']（宋体-简）
            elif system == 'Linux':
                # Linux系统常见中文字体
                plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei']
                # 备选字体：['DejaVu Sans']、['Noto Sans CJK SC']
            # 解决负号显示异常的问题
            plt.rcParams['axes.unicode_minus'] = False
        except Exception as e:
            print(f"设置中文字体失败，将使用默认字体：{e}")

if __name__ == '__main__':
    try:
        cu = ClusterUtils()
        cu.get_k()
    except Exception as e:
        print(f"程序运行失败：{e}")
